package event

import (
	"reflect"

	"soluty.cc/go/xlog"
)

type Emitter struct {
	listeners map[Type][]*listenerItem
	callDepth map[Type]int
	events map[Type]Event
}

type listenerItem struct {
	Listener Listener
	key reflect.Value
}

func NewEmitter() *Emitter {
	em := &Emitter{
		listeners: map[Type][]*listenerItem{},
	}
	return em
}

func (em *Emitter) On(typ Type, listener Listener) {
	key := reflect.ValueOf(listener)
	em.listeners[typ] = append(em.listeners[typ], &listenerItem{key: key, Listener: listener})
}

func (em *Emitter) Off(typ Type, listener Listener) {
	key := reflect.ValueOf(listener)
	for idx, value := range em.listeners[typ] {
		if value.key == key {
			em.listeners[typ] = append(em.listeners[typ][:idx], em.listeners[typ][idx+1:]...)
			return
		}
	}
	xlog.Error(xlog.Errorf("移除不存在的监听器%v", key))
}

func (em *Emitter) Fire(typ Type, params ...map[string]interface{}) error {
	e := NewBase(typ, params...)
	err := em.FireEvent(e)
	return err
}

func (em *Emitter) FireEvent(e Event) (retErr error) {
	defer xlog.Recover(&retErr)
	if em.callDepth == nil {
		em.callDepth = map[Type]int{}
	}
	defer func() {
		em.callDepth = nil
	}()
	em.callDepth[e.Type()] ++
	if em.callDepth[e.Type()] > 3 {
		_args := xlog.Args(e.Type(), e.GetAll())
		return xlog.Errorf("FireEvent%v\n%v", _args, "事件嵌套过深, 可能循环嵌套了")
	}
	for _, l := range em.listeners[e.Type()] {
		err := l.Listener.Handle(e)
		if err != nil {
			_args := xlog.Args(e.Type(), e.GetAll())
			return xlog.Errorf("FireEvent%v\n%w", _args, err)
		}
	}
	return nil
}
